﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AV;

namespace iSchema
{
    class SchemaLine
    {
        public string FieldName = "";
        public string FieldType = "";

        /// <summary>
        /// Attributes of field - @Persistence, etc...
        /// </summary>
        public string[] FieldAttibutes = null;

        public void SetAttribute(string attibuteName)
        {
            if( FieldAttibutes == null )
            {
                FieldAttibutes = new string[] { attibuteName };
            }
        }

        public string GetAttributesDefinition()
        {
            if( FieldAttibutes != null )
            {
                return string.Join(Environment.NewLine, FieldAttibutes);
            }

            return "";
        }

        public string GetFieldName()
        {
            if( !string.IsNullOrEmpty(this.FieldName) )
            {
                return (FieldName.Length == 1) ? FieldName.ToLower() : FieldName.Substring(0, 1).ToLower() + FieldName.Substring(1, FieldName.Length - 1);
            }

            return "";
        }

        public static SchemaLine Parse(string line)
        {
            SchemaLine sl = new SchemaLine();
            string[] ar = line.Split(new char[] { ':' });
            if(ar.Length == 2)
            {
                sl.FieldName = Common.CamelCaseIt(ar[0].Trim(), false);
                sl.FieldType = Common.GetNativeType(ar[1].Trim(), SchemaTypes.JavaDataObject);
            } else
            {
                Log4cs.Log(Importance.Warning, "Incorrect schema line: [{0}]", line);
            }
            return sl;
        }
    }

    class SchemaClass
    {
        /// <summary>
        /// Name of class
        /// </summary>
        public string ClassName = "";

        /// <summary>
        /// Contains array w/ descriptions of all fields
        /// </summary>
        public SchemaLine[] Lines = null;

        /// <summary>
        /// Tries to parse array of lines to schema class. First line should be name of class, others should be intented
        /// </summary>
        /// <param name="arLines"></param>
        /// <returns></returns>
        public static SchemaClass Parse(string[] arLines)
        {
            SchemaClass sc = new SchemaClass();

            try
            {
                sc.ClassName = arLines[0].Trim();
                if(sc.ClassName.EndsWith(":"))
                {
                    sc.ClassName = sc.ClassName.Substring(0, sc.ClassName.Length - 1);
                    sc.ClassName = Common.CamelCaseIt(sc.ClassName, false);

                    SchemaLine[] arProperties = new SchemaLine[arLines.Length];
                    int totalP = 0;
                    for(int i = 1; i < arLines.Length; i++)
                    {
                        SchemaLine sl = SchemaLine.Parse(arLines[i]);
                        Log4cs.Log("Got property: {0} as {1}...", sl.FieldName, sl.FieldType);
                        if(!string.IsNullOrEmpty(sl.FieldName))
                        {
                            sl.SetAttribute("@Persistence");
                            arProperties[totalP++] = sl;
                        }
                    }
                    sc.Lines = arProperties;
                }
                Log4cs.Log("Class name is: {0}", sc.ClassName);
            } catch(Exception ex)
            {
                Log4cs.Log(Importance.Error, "Error parsing schema class lines!");
                Log4cs.Log(Importance.Debug, ex.ToString());
            }

            return sc;
        }

        public static string CreateClassStructure(SchemaClass sc)
        {
            StringBuilder sb = new StringBuilder();
            try
            {
                if(!string.IsNullOrEmpty(sc.ClassName))
                {
                    string classL = "public class {1}{0}[{0}\t// Properties{0}{2}{0}\t// Getters{0}{3}{0}\t// Setters{0}{4}]";
                    sb.AppendFormat(
                            classL
                            , Environment.NewLine
                            , sc.ClassName
                            , sc.GetPropertiesDefinition()
                            , sc.GetGettersDefinitions()
                            , sc.GetSetterDefinitions()
                        );

                }
            } catch(Exception ex)
            {
                Log4cs.Log(Importance.Error, "Error creating class structure!");
                Log4cs.Log(Importance.Debug, ex.ToString());
            }

            return sb.ToString();
        }

        private string GetPropertiesDefinition()
        {
            StringBuilder sb = new StringBuilder();
            if(this.Lines != null)
            {
                for(int i = 0; i < this.Lines.Length; i++)
                {
                    SchemaLine sl = this.Lines[i];
                    if(sl != null)
                    {
                        sb.AppendFormat("\t{1}{0}\tprivate {2} m_{3};{0}", Environment.NewLine, sl.GetAttributesDefinition(), sl.FieldType, sl.GetFieldName());
                    }
                }
            }

            return sb.ToString();
        }

        private string GetGettersDefinitions()
        {
            StringBuilder sb = new StringBuilder();
            if(this.Lines != null)
            {
                for(int i = 0; i < this.Lines.Length; i ++ )
                {
                    SchemaLine sl = this.Lines[i];
                    if( sl != null )
                    {
                        sb.AppendFormat("\tpublic {1} get{2}(){0}\t[{0}\t\treturn this.m_{3};{0}\t]{0}{0}", Environment.NewLine, sl.FieldType, sl.FieldName, sl.GetFieldName());
                    }
                }
            }

            return sb.ToString();
        }

        private string GetSetterDefinitions()
        {
            StringBuilder sb = new StringBuilder();
            if(this.Lines != null)
            {
                for(int i = 0; i < this.Lines.Length; i++)
                {
                    SchemaLine sl = this.Lines[i];
                    if(sl != null)
                    {
                        sb.AppendFormat("\tpublic void set{2}( {1} v ){0}\t[{0}\t\tthis.m_{3} = v;{0}\t]{0}{0}", Environment.NewLine, sl.FieldType, sl.FieldName, sl.GetFieldName());
                    }
                }
            }

            return sb.ToString();
        }

    }
}
